package com.hmi.simulatedrive.activity;

import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;

import com.amap.api.location.CoordinateConverter;
import com.amap.api.location.DPoint;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdate;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.navi.AMapNaviViewOptions;
import com.amap.api.navi.enums.MapStyle;
import com.amap.api.navi.enums.NaviType;
import com.amap.api.navi.model.AMapCalcRouteResult;
import com.amap.api.navi.model.NaviInfo;
import com.amap.api.navi.model.NaviLatLng;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.amap.api.services.help.Inputtips;
import com.amap.api.services.help.Tip;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.SPUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.google.protobuf.InvalidProtocolBufferException;
import com.hmi.simulatedrive.R;
import com.hmi.simulatedrive.databinding.ActivityMainBinding;
import com.hmi.simulatedrive.fragment.CarControlFragment;
import com.hmi.simulatedrive.fragment.CarControlFragmentViewModel;
import com.hmi.simulatedrive.fragment.SettingFragment;
import com.hmi.simulatedrive.fragment.TipSearchFragment;
import com.hmi.simulatedrive.fragment.UnityFragment;
import com.hmi.simulatedrive.fragment.WebRTCFragment;
import com.hmi.simulatedrive.protobuf.HMIPanelModel;
import com.hmi.simulatedrive.protobuf.LocationModel;
import com.hmi.simulatedrive.protobuf.SIMStatusModel;
import com.hmi.simulatedrive.utils.BackHandlerHelper;
import com.hmi.simulatedrive.utils.Constant;
import com.unity3d.player.IUnityPlayerLifecycleEvents;
import com.unity3d.player.MultiWindowSupport;
import com.unity3d.player.UnityPlayer;

import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;

import java.nio.ByteBuffer;
import java.util.LinkedHashSet;
import java.util.concurrent.CopyOnWriteArraySet;

import ademar.phasedseekbar.PhasedListener;
import ademar.phasedseekbar.SimplePhasedAdapter;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class MainActivity extends BaseActivity implements IUnityPlayerLifecycleEvents, View.OnClickListener {
    private View nextTurnRootView,layerUnity;
    private TextView tvNextRoadName, tvNextDistance;
    private ImageView imgNextTurn;
    private UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
    private UnityFragment mUnityFragment;
    private WebRTCFragment webRTCFragment;
    private ActivityMainBinding activityMainBinding; // 当前界面的根View
    private Marker endMaker;
    private CarControlFragmentViewModel carControlFragmentViewModel;
    private int[] defaultIconTypes = {R.drawable.caricon,
            R.drawable.caricon, R.drawable.amap_navi_lbs_sou2, R.drawable.amap_navi_lbs_sou3,
            R.drawable.amap_navi_lbs_sou4, R.drawable.amap_navi_lbs_sou5, R.drawable.amap_navi_lbs_sou6, R.drawable.amap_navi_lbs_sou7,
            R.drawable.amap_navi_lbs_sou8, R.drawable.amap_navi_lbs_sou9, R.drawable.amap_navi_lbs_sou10,
            R.drawable.amap_navi_lbs_sou11, R.drawable.amap_navi_lbs_sou12, R.drawable.amap_navi_lbs_sou13,
            R.drawable.amap_navi_lbs_sou14, R.drawable.amap_navi_lbs_sou15, R.drawable.amap_navi_lbs_sou16,
            R.drawable.amap_navi_lbs_sou17, R.drawable.amap_navi_lbs_sou18, R.drawable.amap_navi_lbs_sou7, R.drawable.amap_navi_lbs_sou20
    };
    private ImageView imgSetting, imgChangeMapStyle, imgNavigation;
    private GeocodeSearch geocoderSearch = null;
    private Inputtips inputTips = null;
    private String cityCode = null;
    private ZMQ.Socket subscriber, controllerRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        activityMainBinding = ActivityMainBinding.inflate(LayoutInflater.from(this));
        setContentView(activityMainBinding.getRoot());

        carControlFragmentViewModel = new ViewModelProvider(MainActivity.this).get(CarControlFragmentViewModel.class);
        initMap(savedInstanceState);

        initGeoSearch();

        initUnityView();

        initJeroMQ();

        initView();
    }

    private void initGeoSearch() {
        try {
            geocoderSearch = new GeocodeSearch(MainActivity.this);
            geocoderSearch.setOnGeocodeSearchListener(onGeocodeSearchListener);
        } catch (AMapException e) {
            throw new RuntimeException(e);
        }
    }

    private void initMap(Bundle savedInstanceState) {
        mAMapNaviView = activityMainBinding.naviView;
        mAMapNaviView.onCreate(savedInstanceState);
        mAMapNaviView.setAMapNaviViewListener(this);

        AMapNaviViewOptions options = new AMapNaviViewOptions();
        options.setTilt(0);
        options.setAutoLockCar(true);
        options.setLockMapDelayed(3000L);
        options.setMapStyle(MapStyle.NIGHT, null);
        options.setSettingMenuEnabled(false);
        options.setLayoutVisible(false);
        options.setPointToCenter(0.67f, 0.5f);
        mAMapNaviView.setViewOptions(options);

        nextTurnRootView = activityMainBinding.layerNavinfo;
        imgNextTurn = activityMainBinding.imgTurnIcon;
        tvNextDistance = activityMainBinding.tvNextTurnDistance;
        tvNextRoadName = activityMainBinding.tvNextRoadName;
        layerUnity = activityMainBinding.layoutUnityFragment;

        mAMapNaviView.getMap().setMyLocationEnabled(true);
        // 长按地图默认为选择终点
        mAMapNaviView.getMap().setOnMapLongClickListener(new AMap.OnMapLongClickListener() {
            @Override
            public void onMapLongClick(LatLng latLng) {
                showEndMarker(latLng);
            }
        });
    }

    private void showEndMarker(LatLng latLng) {
        eList.clear();
        eList.add(new NaviLatLng(latLng.latitude, latLng.longitude));
        if (endMaker != null) {
            endMaker.remove();
        }
        endMaker = mAMapNaviView.getMap().addMarker(new MarkerOptions()
                .icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
                        .decodeResource(getResources(), R.mipmap.end)))
                .position(latLng));
        ToastUtils.showShort("添加终点成功！");
        // 地图自动跳转到新增的终点位置
        CameraUpdate endCamera = CameraUpdateFactory.newLatLng(latLng);
        mAMapNaviView.getMap().animateCamera(endCamera);
    }

    private void initUnityView() {
        // 初始化unity界面
        String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity"));
        getIntent().putExtra("unity", cmdLine);

        mUnityPlayer = new UnityPlayer(this, this);
        Constant.INSTANCE.setMUnityPlayer(mUnityPlayer);
        // 显示unity的fragmen
        if (mUnityFragment == null) {
            mUnityFragment = new UnityFragment();
        }
        getSupportFragmentManager().beginTransaction()
                .add(R.id.layout_unity_fragment, mUnityFragment)
                .commit();
        // 显示webrtc的fragmen
        if (webRTCFragment == null) {
            webRTCFragment = new WebRTCFragment();
        }
        getSupportFragmentManager().beginTransaction()
                .add(R.id.layer_webrtc, webRTCFragment)
                .commit();
    }

    private void initView() {
        imgNavigation = activityMainBinding.imgNavigation;
        imgChangeMapStyle = activityMainBinding.imgChangeStyle;
        imgSetting = activityMainBinding.imgSetting;

        imgSetting.setOnClickListener(this::onClick);
        imgNavigation.setOnClickListener(this::onClick);
        activityMainBinding.imgCarControl.setOnClickListener(this::onClick);
        imgChangeMapStyle.setOnClickListener(this::onClick);
        activityMainBinding.tvAppVersion.setText(AppUtils.getAppVersionName());
        activityMainBinding.edtEnd.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) { // 获取焦点，则自动跳转到搜索界面
                    if (cityCode == null) {
                        ToastUtils.showShort("无法获取当前城市位置！");
                        v.clearFocus();
                        return;
                    }
                    TipSearchFragment tipSearchFragment = new TipSearchFragment();
                    Bundle bundle = new Bundle();
                    bundle.putString("name", activityMainBinding.edtEnd.getText().toString());
                    bundle.putString("city", cityCode);
                    tipSearchFragment.setArguments(bundle);
                    getSupportFragmentManager().beginTransaction()
                            .add(R.id.layer_content_right, tipSearchFragment)
                            .addToBackStack("TipSearchFragment")
                            .commit();
                    v.clearFocus(); // 清除获取焦点的状态
                }
            }
        });
        activityMainBinding.tvSearchEnd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                activityMainBinding.edtEnd.setText("");
            }
        });

        // 切换档位设置
        activityMainBinding.seekbarShiftSwitch.setAdapter(new SimplePhasedAdapter(getResources(),
                new int[]{R.drawable.selector_shift_p, R.drawable.selector_shift_r,
                        R.drawable.selector_shift_n, R.drawable.selector_shift_d}));
        activityMainBinding.seekbarShiftSwitch.setListener(new PhasedListener() {
            @Override
            public void onPositionSelected(int position) {
                HMIPanelModel.HmiPanel.Builder hmiPanelBuilder = carControlFragmentViewModel
                        .getHMIPanelBuilder();
                if (position == 0) {
                    hmiPanelBuilder.setShiftV(0);
                } else if (position == 1) {
                    hmiPanelBuilder.setShiftV(1);
                } else if (position == 2) {
                    hmiPanelBuilder.setShiftV(2);
                } else if (position == 3) {
                    hmiPanelBuilder.setShiftV(3);
                }
                sendHMIControlMessage(hmiPanelBuilder.build());
            }
        });
        carControlFragmentViewModel.getCarControlLiveData().observe(MainActivity.this, new Observer<SIMStatusModel.SimStatus>() {
            @Override
            public void onChanged(SIMStatusModel.SimStatus simStatus) {
                if (simStatus.getShiftV()!=activityMainBinding.seekbarShiftSwitch.getCurrentItem()) {
                    activityMainBinding.seekbarShiftSwitch.setPosition(simStatus.getShiftV());
                }
                // 判断当前的驾驶方向，如果是倒车模式，则自动展示倒车影像
                if (simStatus.getShiftV() == 1) { // 倒车
                    activityMainBinding.layerWebrtc.setVisibility(View.VISIBLE);
                } else {
                    activityMainBinding.layerWebrtc.setVisibility(View.GONE);
                }
            }
        });
    }

    public void setEndTip(Tip endTip) {
        if (endTip!=null&&endTip.getPoint()!=null&&endTip.getName()!=null) {
            activityMainBinding.edtEnd.setText(endTip.getName());
            showEndMarker(new LatLng(endTip.getPoint().getLatitude(), endTip.getPoint().getLongitude()));
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.img_setting: // 用户点击设置
                if (getSupportFragmentManager().findFragmentByTag("settingFragment") == null) {
                    // 显示设置对应的fragment
                    getSupportFragmentManager().beginTransaction()
                            .add(R.id.layer_content_right, SettingFragment.Companion.getInstance(), "settingFragment")
                            .addToBackStack("settingFragment")
                            .commit();
                } else {
                    ToastUtils.showShort("已打开控制界面，请勿重复打开！");
                }
                break;
            case R.id.img_change_style: // 用户点击切换地图样式
                AMapNaviViewOptions viewOptions = mAMapNaviView.getViewOptions();
                if (!imgChangeMapStyle.isSelected()) {
                    viewOptions.setMapStyle(MapStyle.DAY, null);
                } else {
                    viewOptions.setMapStyle(MapStyle.NIGHT, null);
                }
                mAMapNaviView.setViewOptions(viewOptions);
                imgChangeMapStyle.setSelected(!imgChangeMapStyle.isSelected());
                break;
            case R.id.img_navigation: // 用户点击导航
                if (imgNavigation.isSelected()) {
                    imgNavigation.setSelected(false);
                    mAMapNavi.stopNavi();
                } else {
                    // 构建导航起终点
                    sList.clear();
                    if (Constant.INSTANCE.getCurrentLocation() == null) {
                        ToastUtils.showShort("无法获取当前位置！");
                        return;
                    }
                    sList.add(new NaviLatLng(Constant.INSTANCE.getCurrentLocation().getLatitude(), Constant.INSTANCE.getCurrentLocation().getLongitude()));

                    if (eList.isEmpty()) {
                        ToastUtils.showShort("没有设置终点，请在地图长按以设置终点！");
                        return;
                    }
                    /**
                     * 方法: int strategy=mAMapNavi.strategyConvert(congestion, avoidhightspeed, cost, hightspeed, multipleroute); 参数:
                     *
                     * @congestion 躲避拥堵
                     * @avoidhightspeed 不走高速
                     * @cost 避免收费
                     * @hightspeed 高速优先
                     * @multipleroute 多路径
                     *
                     *  说明: 以上参数都是boolean类型，其中multipleroute参数表示是否多条路线，如果为true则此策略会算出多条路线。
                     *  注意: 不走高速与高速优先不能同时为true 高速优先与避免收费不能同时为true
                     */
                    int strategy = 0;
                    try {
                        //再次强调，最后一个参数为true时代表多路径，否则代表单路径
                        strategy = mAMapNavi.strategyConvert(true, false, false, false, false);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    mAMapNavi.calculateDriveRoute(sList, eList, mWayPointList, strategy);
                    imgNavigation.setSelected(true);
                }
                break;
            case R.id.img_car_control: // 用户车辆设置
                if (getSupportFragmentManager().findFragmentByTag("carControlFragment") == null) {
                    getSupportFragmentManager().beginTransaction()
                            .add(R.id.layer_content_right, CarControlFragment.Companion.getInstance(), "carControlFragment")
                            .addToBackStack("carControlFragment")
                            .commit();
                } else {
                    ToastUtils.showShort("已打开控制界面，请勿重复打开！");
                }
                break;
        }
    }

    /**
     * 初始化JeroMQ
     * */
    private Thread jeroThread;
    public void initJeroMQ() {
        if (jeroThread!=null) {
            jeroThread.interrupt();
        }
        if (subscriber!=null) {
            subscriber.close();
        }
        if (controllerRequest!=null) {
            controllerRequest.close();
        }
        jeroThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try (ZContext context = new ZContext()) {
                    System.out.println("创建对服务器5567端口的订阅");

                    //  Socket to talk to server
                    String ip = SPUtils.getInstance().getString(Constant.INSTANCE.getSETTING_IP(), Constant.INSTANCE.getDEFAULT_SIM_IP());
                    String locationPort = SPUtils.getInstance().getString(Constant.INSTANCE.getSETTING_LOCATION_PORT(), Constant.INSTANCE.getDEFAULT_LOCATION_PORT());
                    String controllerPort = SPUtils.getInstance().getString(Constant.INSTANCE.getSETTING_LOCATION_PORT(), Constant.INSTANCE.getDEFAULT_CONTROLLER_PORT());
                    subscriber = context.createSocket(SocketType.SUB);
                    boolean isConnect = subscriber.connect("tcp://"+ip+":"+locationPort);

                    //  Subscribe to zipcode, default is NYC, 10001
                    String filter = "";
                    boolean isSubscribe = subscriber.subscribe(filter.getBytes(ZMQ.CHARSET));

                    // 初始化控制协议端口连接
                    controllerRequest = context.createSocket(SocketType.REQ);
                    boolean controllerConnect = controllerRequest.connect("tcp://"+ip+":"+controllerPort);

                    //  Process 100 updates
                    ByteBuffer byteBuffer = ByteBuffer.allocate(50);
                    while (isConnect&&isSubscribe) {
                        //  Use trim to remove the tailing '0' character
                        int byteLength = subscriber.recvByteBuffer(byteBuffer, 0);
                        byteBuffer.flip();
                        byte[] byteResult = new byte[byteLength];
                        byteBuffer.get(byteResult, 0, byteLength);
                        // 解析Byte数据
                        LocationModel.NavData location = LocationModel.NavData.parseFrom(byteResult);
                        byteBuffer.clear();
                        initLocation(location);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.e("ERROR", e.getMessage());
                }
            }
        });
        jeroThread.start();
    }

    /**
     * 通过JeroMQ发送最新的配置信息
     * */
    public void sendHMIControlMessage(
            HMIPanelModel.HmiPanel hmiPanel) {
        // 线程发送最新的控制状态
        if (controllerRequest!=null) {
            Observable.create(new ObservableOnSubscribe<HMIPanelModel.HmiPanel>() {
                        @Override
                        public void subscribe(@io.reactivex.rxjava3.annotations.NonNull ObservableEmitter<HMIPanelModel.HmiPanel> emitter) throws Throwable {
                            byte[] byteArray = hmiPanel.toByteArray();
                            boolean isSend = controllerRequest.send(byteArray);
                            if (isSend) { // 请求发送成功，接收返回值
                                byte[] byteResult = controllerRequest.recv();
                                try {
                                    SIMStatusModel.SimStatus simStatus = SIMStatusModel.SimStatus.parseFrom(byteResult);
                                    // 新获取的控制状态更新到界面
                                    new ViewModelProvider(MainActivity.this).get(CarControlFragmentViewModel.class)
                                            // 将获取的数据更新到livedata，会同步显示到界面
                                            .getCarControlLiveData().postValue(simStatus);
                                } catch (InvalidProtocolBufferException e) {
                                    throw new RuntimeException(e);
                                }
                            } else {
                                Log.e("sendHMIControlMessage", "发送失败");
                            }
                            emitter.onNext(hmiPanel);
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new io.reactivex.rxjava3.core.Observer<HMIPanelModel.HmiPanel>() {
                        @Override
                        public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {

                        }

                        @Override
                        public void onNext(HMIPanelModel.@io.reactivex.rxjava3.annotations.NonNull HmiPanel hmiPanel) {

                        }

                        @Override
                        public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
                            Log.e("sendHMIControlMessage", e.getMessage());
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        }
    }

    @Override
    public void onInitNaviSuccess() {
        super.onInitNaviSuccess();
        mAMapNavi.setIsUseExtraGPSData(true);
    }

    @Override
    public void onCalculateRouteSuccess(AMapCalcRouteResult aMapCalcRouteResult) {
        super.onCalculateRouteSuccess(aMapCalcRouteResult);
        if (SPUtils.getInstance().getBoolean(Constant.INSTANCE.getSETTING_SIMULATE_NAVI(), true)) {
            mAMapNavi.startNavi(NaviType.EMULATOR);
        } else {
            mAMapNavi.startNavi(NaviType.GPS);
        }
    }

    @Override
    public void onStartNavi(int type) {
        super.onStartNavi(type);
        nextTurnRootView.setVisibility(View.VISIBLE);
    }

    @Override
    public void onNaviCancel() {
        super.onNaviCancel();
        nextTurnRootView.setVisibility(View.GONE);
    }

    @Override
    public void onArriveDestination() {
        super.onArriveDestination();
        nextTurnRootView.setVisibility(View.GONE);
    }

    @Override
    public void onNaviInfoUpdate(NaviInfo naviinfo) {
        //导航过程中的信息更新，请看NaviInfo的具体说明
        String nextRoadName = naviinfo.getNextRoadName();
        int curStepDistance = naviinfo.getCurStepRetainDistance();
        int iconType = naviinfo.getIconType();
        setIconType(imgNextTurn, iconType);
        if (curStepDistance<1000) {
            tvNextDistance.setText(curStepDistance+"米");
        } else {
            tvNextDistance.setText(String.format(".2f", curStepDistance/1000.f)+"千米");
        }
        tvNextRoadName.setText(nextRoadName);
    }

    /**
     * 设置自定义的转向图标，请参考{@link com.amap.api.navi.enums.IconType}
     *
     * @param iconType 图片的id
     */
    private long mLastIconType = -1;
    private Bitmap nextTurnBitmap;
    public void setIconType(ImageView imgNextTurn, int iconType) {
        try {
            if (iconType > 20 || mLastIconType == iconType) {
                return;
            }
            recycleResource();
            nextTurnBitmap = BitmapFactory.decodeResource(getResources(), defaultIconTypes[iconType]);
            imgNextTurn.setImageBitmap(nextTurnBitmap);
            mLastIconType = iconType;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放图片资源
     */
    public void recycleResource() {
        try {
            if (nextTurnBitmap != null) {
                nextTurnBitmap.recycle();
                nextTurnBitmap = null;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onUnityPlayerUnloaded() {
//        moveTaskToBack(true);
        ToastUtils.showLong("Unity界面初始化失败！");
    }

    @Override
    public void onUnityPlayerQuitted() {

    }

    @Override protected void onNewIntent(Intent intent) {
        // To support deep linking, we need to make sure that the client can get access to
        // the last sent intent. The clients access this through a JNI api that allows them
        // to get the intent set on launch. To update that after launch we have to manually
        // replace the intent with the one caught here.
        super.onNewIntent(intent);
        setIntent(intent);
        mUnityPlayer.newIntent(intent);
    }

    // Quit Unity
    @Override protected void onDestroy ()
    {
        mUnityPlayer.destroy();
        super.onDestroy();
    }

    // If the activity is in multi window mode or resizing the activity is allowed we will use
    // onStart/onStop (the visibility callbacks) to determine when to pause/resume.
    // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve
    // existing behavior.
    @Override protected void onStop()
    {
        super.onStop();

        if (!MultiWindowSupport.getAllowResizableWindow(this))
            return;

        mUnityPlayer.pause();
    }

    @Override protected void onStart()
    {
        super.onStart();

        if (!MultiWindowSupport.getAllowResizableWindow(this))
            return;

        mUnityPlayer.resume();
    }

    // Pause Unity
    @Override protected void onPause()
    {
        super.onPause();

        MultiWindowSupport.saveMultiWindowMode(this);

        if (MultiWindowSupport.getAllowResizableWindow(this))
            return;

        mUnityPlayer.pause();
    }

    // Resume Unity
    @Override protected void onResume()
    {
        super.onResume();

        if (MultiWindowSupport.getAllowResizableWindow(this) && !MultiWindowSupport.isMultiWindowModeChangedToTrue(this))
            return;

        layerUnity.setVisibility(View.VISIBLE);
        mUnityPlayer.resume();
    }

    // Low Memory Unity
    @Override public void onLowMemory()
    {
        super.onLowMemory();
        mUnityPlayer.lowMemory();
    }

    // Trim Memory Unity
    @Override public void onTrimMemory(int level)
    {
        super.onTrimMemory(level);
        if (level == TRIM_MEMORY_RUNNING_CRITICAL)
        {
            mUnityPlayer.lowMemory();
        }
    }

    // This ensures the layout will be correct.
    @Override public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);
        mUnityPlayer.configurationChanged(newConfig);
    }

    // Notify Unity of the focus change.
    @Override public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);
        mUnityPlayer.windowFocusChanged(hasFocus);
    }

    // For some reason the multiple keyevent type is not supported by the ndk.
    // Force event injection by overriding dispatchKeyEvent().
    @Override public boolean dispatchKeyEvent(KeyEvent event)
    {
        if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
            return mUnityPlayer.injectEvent(event);
        return super.dispatchKeyEvent(event);
    }

    // Pass any events not handled by (unfocused) views straight to UnityPlayer
    @Override public boolean onKeyDown(int keyCode, KeyEvent event)   {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return super.onKeyDown(keyCode, event);
        } else {
            return mUnityPlayer.onKeyDown(keyCode, event);
        }
    }
    @Override public boolean onKeyUp(int keyCode, KeyEvent event)     {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return super.onKeyUp(keyCode, event);
        } else {
            return mUnityPlayer.onKeyUp(keyCode, event);
        }
    }
    @Override public boolean onTouchEvent(MotionEvent event)          { return mUnityPlayer.onTouchEvent(event); }
    @Override public boolean onGenericMotionEvent(MotionEvent event)  { return mUnityPlayer.onGenericMotionEvent(event); }

    protected Location initLocation(LocationModel.NavData locationModel) {
        if (Constant.INSTANCE.getCurrentLocation() == null) {
            Constant.INSTANCE.setCurrentLocation(new Location(LocationManager.GPS_PROVIDER));
        }
        CoordinateConverter converter  = new CoordinateConverter(MainActivity.this);
        converter.from(CoordinateConverter.CoordType.GPS);
        DPoint dPoint = new DPoint();
        dPoint.setLatitude(locationModel.getLatitude());
        dPoint.setLongitude(locationModel.getLongitude());
        try {
            converter.coord(dPoint);
            DPoint convert = converter.convert();
            Constant.INSTANCE.getCurrentLocation().setLatitude(convert.getLatitude());
            Constant.INSTANCE.getCurrentLocation().setLongitude(convert.getLongitude());
        } catch (Exception e) {
            Constant.INSTANCE.getCurrentLocation().setLatitude(locationModel.getLatitude());
            Constant.INSTANCE.getCurrentLocation().setLongitude(locationModel.getLongitude());
            throw new RuntimeException(e);
        }
        Constant.INSTANCE.getCurrentLocation().setAltitude(locationModel.getAltitude());
        Constant.INSTANCE.getCurrentLocation().setSpeed(locationModel.getSpeed());
//        Constant.INSTANCE.getCurrentLocation().setBearing(locationModel.getBearing());
        Constant.INSTANCE.getCurrentLocation().setBearing((90-(float) Math.toDegrees(locationModel.getBearing())+360)%360);
        Constant.INSTANCE.getCurrentLocation().setAccuracy(0.0f);
        Constant.INSTANCE.getCurrentLocation().setTime(System.currentTimeMillis());
        mAMapNavi.setExtraGPSData(1, Constant.INSTANCE.getCurrentLocation());
//        activityMainBinding.layerWebrtc.setVisibility(View.VISIBLE);
        if (geocoderSearch == null) {
            initGeoSearch();
        }
        // 每隔10分钟查询一次行政区划
        if (geocoderSearch!=null&&System.currentTimeMillis()-geoCodeSearchTime>1000*60*10) {
            RegeocodeQuery query = new RegeocodeQuery(new LatLonPoint(Constant.INSTANCE.getCurrentLocation().getLatitude(),
                    Constant.INSTANCE.getCurrentLocation().getLongitude()), 200,GeocodeSearch.GPS);
            geocoderSearch.getFromLocationAsyn(query);
            geoCodeSearchTime = System.currentTimeMillis();
        }
        return Constant.INSTANCE.getCurrentLocation();
    }

    private long geoCodeSearchTime = 0;
    private GeocodeSearch.OnGeocodeSearchListener onGeocodeSearchListener = new GeocodeSearch.OnGeocodeSearchListener() {
        @Override
        public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int i) {
            cityCode = regeocodeResult.getRegeocodeAddress().getCityCode();
        }

        @Override
        public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {

        }
    };
    private boolean isBack = false;
    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            if (msg.what == 0x100) {
                isBack = false;
            }
            return false;
        }
    });
    @Override
    public void onBackPressed() {
        if (!BackHandlerHelper.handleBackPress(this)) {
            if (!isBack) {
                isBack = true;
                Toast.makeText(this, "双击退出程序", Toast.LENGTH_SHORT).show();
                handler.sendEmptyMessageDelayed(0x100, 2000);
            } else {
                finish();
            }
        }
    }
}